from test.testpackage1 import Student
#（直接衔接1.31）注意私有属性不能被继承，即子类不能直接访问父类的私有方法

class Person:
    def __new__(cls, *args, **kwargs):
        print('这是__new__方法')
        #__new__没有返回值的话，就调用不了__init__()
        #下一句return是有必要的
        return object.__new__(cls)#写了这一句才会接着调用__init__()
        #当然，super().__new__(cls)也是一样的（相当于Person是object的子类）
        #本质上是因为调用了父类object上的__new__（）才成功创建了对象，接下来继续执行__init__()
    def __init__(self,name,password):
        self.name=name
        self.__password=password
    def showinfo(self):
        print('名称为{},密码为{}'.format(self.name,self.__password))
Tom=Person('Tom',123456)
Tom.showinfo()#名称为Tom,密码为123456
class s1(Person):
    def __init__(self, name,password):
        super().__init__(name,password)
    def showinfo(self):
        print('欸，不告诉你')
Amy=s1('Amy',123456)
Amy.showinfo()#欸，不告诉你
#多继承：即可以定义多个子类
class s2(Person):
    def __init__(self,name,password):
        super().__init__(name,password)
    def showinfo(self):
        Person.showinfo(self)
        #也可以写成super().showinfo(self),如同我们写super().__init__()的时候一样
        print('扩展了吗，如扩')
Mike=s2('Mike',123456)
Mike.showinfo()
'''
名称为Mike,密码为123456
扩展了吗，如扩
'''
#子类的重写：在子类中定义一个同名的方法，就实现了对父类的重写（覆盖）
#父类的扩展：在子类中调用了父类的同名方法，就可以在子类中对父类进行扩展
'''
me=Student('uni',18,'python','m','123456')
me.share_info()
'''
'''
__new__方法：是在创建对象时第一个调用的方法
为对象在内存中分配空间
'''
'''
单例模式：一个特殊的类，创建这个类的对象时，指向的是同一个内存地址（实际上同时只存在同一个对象）
作用：减少资源的浪费
单例模式的五种实现方法：
1）__new__()
2)使用@classmethod
3）装饰器
4）导入模块
5）元类
'''
#法一（使用__new__）：
class Test(object):
    ins=None
    def __new__(cls, *args, **kwargs):
        if cls.ins is None:
            cls.ins=super().__new__(cls)
        return  cls.ins
t1=Test()
t2=Test()
print(id(t1))#1886838615952
print(id(t2))#1886838615952
#法二(使用@classmethod)：
class Test2(object):
    ins=None
    @classmethod
    def instance(cls):
        if cls.ins is None:
            cls.ins=super().__new__(cls)
        return cls.ins
t3=Test2.instance()
t4=Test2.instance()
print(t3,id(t3))#<__main__.Test2 object at 0x000001FC7C2570E0> 2988704428256
print(t4,id(t4))#<__main__.Test2 object at 0x000001FC7C2570E0> 2988704428256
#操作与1基本相同，区别是1使用__new__()承接，2使用@classmethod定义的类方法承接，所以不能直接定义，需要调用方法
#法三（使用装饰器，但是@classmethod难道不也是装饰器吗）：
def outer(fn):
    _ins={}
    def inner():
        if fn not in _ins:
            print(fn())#<__main__.Test3 object at 0x000001A4EB737230>
            print(_ins)#{}
            print('————————')
            _ins[fn]=fn()
            print(_ins)#{<class '__main__.Test3'>: <__main__.Test3 object at 0x000001A4EB914910>}
    return inner
#实质是将类名传入了字典，保证只调用一次
@outer
class Test3(object):
    a=1
t5=Test3()
t6=Test3()
print(t5,id(t5))#None 140720667066864
print(t6,id(t6))#None 140720667066864
#法四（导入模块）：
#导入的模块是天然的单例模式

#法五（元类）使用hasattr()：
#hasattr()函数用于判断类中是否拥有某个属性
#语法hasattr(类名（）,str)，如果str是类中的属性就返回True，否则返回False
class Test4(object):
    b=2
    def fi(self):
        print('这是fi')
print(hasattr(Test4(),'b'))#TruE
print(hasattr(Test4(),'fi'))#TruE
#开始使用hasattr()
class Test5(object):
    def __init__(self,name):
        self.name=name
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls,'ins'):
            cls.ins=super().__new__(cls)
        return cls.ins
test7=Test5('uni')
test8=Test5('uny')
print(id(test7))#2517889282608
print(id(test8))#2517889282608
print(test7.name,test8.name)#uny uny